// =================================================================
// File: open.cpp
// Desc: Contains function for opening a file
// =================================================================

// =================================================================
// INCLUDES
// =================================================================

#include <string>
#include <ctime>
#include "FSManager.h"
#include "File.h"
#include "Inode.h"
#include "config.h"
#include "commands.h"

using namespace std;
// =================================================================
// FUNCTIONS
// =================================================================

// =================================================================
// Name: convert_mode
// Desc: Converts the string argument, to the corresponding number related
//       for that mode
// Args: string mode - the string form of the mode that is needed.
// Rets: the number for the mode that was used
// =================================================================
int convert_mode(string mode){
    if(mode == "r")
        return READ_MODE;
    else if(mode == "w")
        return WRITE_MODE;
    else if(mode == "rw")
        return READWRITE_MODE;
    else
        return -1;
}

// =================================================================
// Name: open
// Desc: Opens the file at the given path, in the given mode.
// Args: string path - the path to a file, or just the filename
//       string str_mode - the string representation of the mode.
//       FSManager* fsm - pointer to FSManager object in use
// Rets: the file descriptor that now corresponds to the file
// =================================================================
int open(string path, string str_mode, FSManager *fsm) {

    // Check to see if the file exists
    string filename;
    size_t found;
    File *file;
    Inode *node;
    int inode_index;
    int fd;
    int mode = convert_mode(str_mode);

    if(mode == -1)
        return -1;

    found = path.find_last_of("/");
    Directory *dir;

    if (found == string::npos) {
        dir = fsm->GetCurrentDirectory();
    } else {
        dir = fsm->ReadDirectory(path.substr(0,found));
    }

    if (dir == NULL) {
        cerr << "Directory does not exist" << endl;
        return -1;
    }

    filename = path.substr(found+1);

    // If it doesn't exist, create it
    if ((dir->GetEntry(filename) == -1) && (mode == WRITE_MODE || mode == READWRITE_MODE)) {
        inode_index = fsm->GetSB()->FreeInodePop();
        node = new Inode();
        node->SetNumLinks(1);
        node->SetAccessed(time(0));
        node->SetChanged(time(0));
        node->SetModified(time(0));

        fsm->WriteInode(node,inode_index);
        delete node;

        fd = fsm->GetNextAvailableFD();

        file = new File(fd,inode_index,mode,0);

        dir->InsertEntry(filename,inode_index);

        fsm->WriteDirectory(dir);

        fsm->InsertOpenFile(fd,file);
    }

    else if((inode_index = dir->GetEntry(filename)) != -1){
        fd = fsm->GetNextAvailableFD();
        file = new File(fd,inode_index,mode,0);
        fsm->InsertOpenFile(fd,file);

    }
    if(dir->GetInodeIndex() != fsm->GetCurrentDirectory()->GetInodeIndex())
    { 
      if (dir != fsm->GetCurrentDirectory())
        delete dir;
    }

    return fd;
}
